{#
Copyright 2024 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

#}{% extends 'base.html' %}

{% block content %}

<style>
td .benchmark .function,
td .signature {
    overflow-wrap: anywhere;
}

td .signature {
    width: fit-content;
    white-space: normal;
    padding: 5px 2px;
    margin: 5px 0 0;
    background: #eee;
    font-family: monospace;
    font-size: 14px;
}

.signature a {
    text-decoration: none;
}

.table-index {
    color: #555;
    font-size: 12px;
    text-align: center;
}


.sortable-table th {
    cursor: pointer;
}

.sortable-table th:after {
    content: ' \25be';
    color: #ccc;
}

.sortable-table th[data-sorted="asc"]:after {
    color: #000;
}

.sortable-table th[data-sorted="desc"]:after {
    content: ' \25b4';
    color: #000;
}

</style>

<table class="sortable-table" id="benchmark-table">
    <thead>
        <tr>
            <th></th>
            <th data-sorted="asc">Benchmark</th>
            <th>Status</th>
            <th data-sort-number>Build Rate</th>
            <th data-sort-number>Crash Rate</th>
            <th data-sort-number>Bugs</th>
            <th data-sort-number>Program Counter Coverage</th>
            <th data-sort-number>Line Coverage Diff</th>
        </tr>
    </thead>
    <tbody>
        {% for benchmark in benchmarks %}
        <tr>
            <td class="table-index">{{ loop.index }}</td>
            <td data-sort-value="{{ benchmark.id }}">
                <div class="project">{{ benchmark.project }}</div>
                <pre class="signature">
                    <a href="benchmark/{{ benchmark.id|urlencode }}/index.html">{{ benchmark.signature }}</a>
                </pre>
            </td>
            <td data-sort-value="{{ benchmark.status }}">{{ benchmark.status }}</td>
            <td data-sort-value="{{ benchmark.result.build_success_rate|percent }}">{{ benchmark.result.build_success_rate|percent}}</td>
            <td data-sort-value="{{ benchmark.result.crash_rate|percent }}"><a href="benchmark/{{ benchmark.id|urlencode }}/crash.json"> {{ benchmark.result.crash_rate|percent }} </a></td>
            <td data-sort-value="{{ benchmark.result.found_bug }}">{{ benchmark.result.found_bug }}</td>
            <td data-sort-value="{{ benchmark.result.max_coverage |percent }}">{{ benchmark.result.max_coverage |percent }}</td>
            <td data-sort-value="{{ benchmark.result.max_line_coverage_diff|percent }}"><a href="{{ benchmark.result.max_coverage_diff_report | cov_report_link }}">{{ benchmark.result.max_line_coverage_diff|percent }}</a></td>
        </tr>
        {% endfor %}
    </tbody>
</table>

<h2>Project summary</h2>
<table class="sortable-table" id="summary-table">
    <thead>
        <tr>
            <th></th>
            <th data-sorted="asc">Project</th>
            <th data-sort-number>Total benchmarks</th>
            <th data-sort-number>Successful benchmarks</th>
            <th data-sort-number>Total coverage gain</th>
            <th data-sort-number>Total relative gain</th>
            <th data-sort-number>OSS-Fuzz-gen total covered lines</th>
            <th data-sort-number>OSS-Fuzz-gen new covered lines</th>
            <th data-sort-number>Existing covered lines</th>
            <th data-sort-number>Total project lines</th>
        </tr>
    </thead>
    <tbody>
        {% for project in projects %}
        <tr>
            <td class="table-index">{{ loop.index }}</td>
            <td data-sort-value="{{ project.name }}">{{ project.name }}</td>
            <td data-sort-value="{{ project.count }}">{{ project.count }}</td>
            <td data-sort-value="{{ project.success }}">{{ project.success }}</td>
            <td data-sort-value="{{ project.coverage_gain|percent }}">{{ project.coverage_gain|percent }}%</td>
            <td data-sort-value="{{ project.coverage_relative_gain|percent}}">{{ project.coverage_relative_gain | percent }}%</td>
            <td data-sort-value="{{ project.coverage_ofg_total_covered_lines}}">{{project.coverage_ofg_total_covered_lines}}</td>
            <td data-sort-value="{{ project.coverage_ofg_total_new_covered_lines}}">{{ project.coverage_ofg_total_new_covered_lines}}</td>
            <td data-sort-value="{{ project.coverage_existing_total_covered_lines}}">{{ project.coverage_existing_total_covered_lines}}</td>
            <td data-sort-value="{{ project.coverage_existing_total_lines}}">{{ project.coverage_existing_total_lines}}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

<h2>Language coverage gains</h2>
<table class="sortable-table" id="language-coverage-gain">
    <thead>
        <th>language</th>
        <th>OSS-Fuzz total lines</th>
        <th>OSS-Fuzz coverage lines</th>
        <th>Experiment new coverage lines</th>
        <th>Increase of total</th>
        <th>Increase of covered</th>
    </thead>
    <tbody>
        {% for language in coverage_language_gains['coverage_gains_per_language'] %}
        <tr>
            <td>{{language}}</td>
            <td>{{coverage_language_gains['oss_fuzz_language_status'][language]['total']}}</td>
            <td>{{coverage_language_gains['oss_fuzz_language_status'][language]['covered']}}</td>
            <td>{{coverage_language_gains['coverage_gains_per_language'][language]}}</td>
            <td>{{coverage_language_gains['comperative_coverage_gains'][language]['total_coverage_increase']}}%</td>
            <td>{{coverage_language_gains['comperative_coverage_gains'][language]['relative_coverage_increase']}}%</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

<h2>Crashes found by generated fuzz harnesses</h2>
<table class="sortable-table" id="bug-summary-table">
    <thead>
        <tr>
            <th></th>
            <th data-sort-string>Project</th>
            <th data-sorted="asc">Benchmark</th>
            <th data-sort-string>AI bug validation</th>
        </tr>
    </thead>
    <tbody>
        {% for bug_sample in samples_with_bugs %}
        <tr>
            <td class="table-index">{{ loop.index }}</td>
            <td data-sort-value="{{bug_sample.benchmark.project}}">{{bug_sample.benchmark.project}}</td>
            <td data-sort-value="{{bug_sample.benchmark.id}}"><a href="sample/{{ bug_sample.benchmark.id|urlencode }}/{{ bug_sample.sample.id }}.html">{{bug_sample.benchmark.id}}-{{ bug_sample.sample.id }} </a> </td>
            <td style="color: {{ 'red' if bug_sample.sample.result.crashes and not bug_sample.sample.result.is_semantic_error else 'green' }}" data-sort-value="{{'True positive' if bug_sample.sample.result.is_semantic_error else 'False positive'}}">{{'True positive' if bug_sample.sample.result.is_semantic_error else 'False positive'}}</td>
        </tr>
        {% endfor %}
    </tbody>
</table>

<h2>Accumulated results</h2>
<table>
  <thead>
    <th>Metric</th>
    <th>Value</th>
  </thead>
  <tbody>
    <tr>
      <td>Total sample benchmarks</td>
      <td>{{ accumulated_results.total_runs }}</td>
    </tr>
    <tr>
      <td>Successful Builds</td>
      <td>{{ accumulated_results.compiles }}</td>
    </tr>
    <tr>
      <td>Build rate</td>
      <td>{{ accumulated_results.build_rate |percent }}%</td>
    </tr>
    <tr>
      <td>Average coverage</td>
      <td>{{ accumulated_results.average_coverage |percent }}%</td>
    </tr>
    <tr>
      <td>Average line coverage diff</td>
      <td>{{ accumulated_results.average_line_coverage_diff |percent }}%</td>
    </tr>
    <tr>
      <td>Benchmarks with crashes</td>
      <td>{{ accumulated_results.crashes }}</td>
    </tr>
    <tr>
        <td>Experiment start time</td>
        <td>{{time_results.start_time}}</td>
    </tr>
    <tr>
        <td>Experiment end time</td>
        <td>{{time_results.completion_time}}</td>
    </tr>
    <tr>
        <td>Experiment total run time</td>
        <td>{{time_results.total_run_time}}</td>
    </tr>
  </tbody>
</table>

<script>
(function() {
    tables = Array.from(document.querySelectorAll('table.sortable-table'));
    for (let tbl_idx1 = 0; tbl_idx1 < tables.length; tbl_idx1++) {
        table_element = tables[tbl_idx1];
        const table_id_name = table_element.id;
        headers = Array.from(table_element.querySelectorAll('th'));
        headers.map(
            (th, colindex) => th.addEventListener('click', () => {
                const sortAsc = th.dataset.sorted != "asc";
                const sortNumber = th.dataset.sortNumber != undefined;

                // Move sorted data attribute to the right column
                headers.map(innerTH => delete innerTH.dataset.sorted);
                th.dataset.sorted = sortAsc ? "asc" : "desc";

                // Find the relevant table and sort it accordingly.
                inner_tables = Array.from(document.querySelectorAll('table.sortable-table'));
                for (let tbl_idx2 = 0; tbl_idx2 < inner_tables.length; tbl_idx2++) {
                    the_table = inner_tables[tbl_idx2];
                    if (the_table.id == table_id_name) {
                        const tbody = the_table.querySelector('tbody');
                        const rows = Array.from(tbody.children);
                        rows.sort((a, b) => {
                            let [valueA, valueB] = [a.children[colindex].dataset.sortValue, b.children[colindex].dataset.sortValue];
                            // Swap the values for descending.
                            if (!sortAsc) {
                                [valueB, valueA] = [valueA, valueB];
                            }

                            if (sortNumber) {
                                return Number(valueB) - Number(valueA);
                            }
                            return valueA.localeCompare(valueB);
                        });
                        tbody.replaceChildren(...rows);
                        // Rewrite the index column
                        rows.map((r, i) => r.children[0].innerText = i);
                    }
                }
            }, )
        );

    }
})();
</script>
{% endblock %}
